package service;

import org.redisson.Redisson;
import org.redisson.api.*;
import org.redisson.config.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.TimeUnit;

//@Service
public class RedissonService {
    private static Logger logger = LoggerFactory.getLogger(RedissonService.class);

    public static void reentrantLock1(RedissonClient redisson, String key, long waitMillis, long leaseMillis) {
        RLock lock = redisson.getLock(key); //重入锁
//        RLock lock = redisson.getFairLock(key);// 公平锁
//        RedissonMultiLock lock = new RedissonMultiLock(lock1, lock2); // 联锁
//        RedissonRedLock lock = new RedissonRedLock(lock1, lock2); // 红锁
//        RReadWriteLock lock = (RReadWriteLock) redisson.getLock(key);
        lock.lock();
        try{
            boolean isLocked = lock.tryLock(waitMillis, leaseMillis, TimeUnit.MILLISECONDS);
            if(isLocked){
//                doSomething()
            }
        } catch (InterruptedException e) {
            logger.error("", e);
        } finally {
            lock.unlock(); //java.lang.IllegalMonitorStateException: attempt to unlock lock, not locked by current thread by node id
        }
    }


    public static void testCountDownLatch(RedissonClient redisson, String key, int count) throws InterruptedException {
        RCountDownLatch latch = redisson.getCountDownLatch(key);
        latch.trySetCount(count);
        //
        for (int i = 0; i < count; i++) {
            new Thread(() -> {
                RCountDownLatch latch1 = redisson.getCountDownLatch(key);
                latch1.countDown();
                System.out.println("A: " + System.currentTimeMillis()/1000 + ", thread: " + Thread.currentThread().getName());
            }).start();
        }
        //
        latch.await(); // 阻塞
        System.out.println("B: " + System.currentTimeMillis()/1000 + ", thread: " + Thread.currentThread().getName());
    }

    public static void testSemaphore(RedissonClient redisson, String key, int permits) {
        RSemaphore semaphore = redisson.getSemaphore(key);
        semaphore.trySetPermits(permits);
        //
        for (int i = 0; i < permits; i++) {
            new Thread(() -> {
                try {
                    RSemaphore semaphore1 = redisson.getSemaphore(key);
                    semaphore1.acquire(1); //semaphore.tryAcquire()
                    Thread.sleep(1000L);
                    System.out.println("A: " + System.currentTimeMillis()/1000 + ", thread: " + Thread.currentThread().getName());
                    semaphore1.release(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }

    public static void testPermitExpirableSemaphore(RedissonClient redisson, String key, int permits) {
        RPermitExpirableSemaphore  semaphore = redisson.getPermitExpirableSemaphore(key);
        semaphore.trySetPermits(permits);
        //
        for (int i = 0; i < permits; i++) {
            new Thread(() -> {
                try {
                    RPermitExpirableSemaphore  semaphore1 = redisson.getPermitExpirableSemaphore(key);
                    String permitId = semaphore1.acquire();
//                    String permitId = semaphore1.acquire(1, TimeUnit.SECONDS);
                    Thread.sleep(1000L);
                    System.out.println("A: " + System.currentTimeMillis()/1000 + ", thread: " + Thread.currentThread().getName());
                    semaphore1.release(permitId);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }

    public static void testReadWriteLock(RedissonClient redisson, String key,long leaseMillis){
        RReadWriteLock lock = redisson.getReadWriteLock(key);
        lock.readLock().lock();
        lock.writeLock().lock();
        lock.readLock().lock(10, TimeUnit.SECONDS);
        lock.writeLock().lock(10, TimeUnit.SECONDS);
//        boolean res = lock.readLock().tryLock(100, 10, TimeUnit.SECONDS);
//        boolean res = lock.writeLock().tryLock(100, 10, TimeUnit.SECONDS);
        lock.readLock().unlock();
        lock.writeLock().unlock();
    }

    public static void main(String[] args) throws InterruptedException {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://192.168.3.7:6379");
        RedissonClient redisson = Redisson.create(config);
        String key = "name";
        for (int i = 0; i < 2; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    reentrantLock(redisson, key, 0L, 120000L);
                }
            }).start();
        }
        Thread.sleep(100000L);
        redisson.shutdown();
    }

    public static void reentrantLock(RedissonClient redisson, String key, long waitMillis, long leaseMillis) {
        RLock lock = redisson.getLock(key);
        try{
            boolean isLocked = lock.tryLock(waitMillis, leaseMillis, TimeUnit.MILLISECONDS);
            if(!isLocked) {
                return;
            }
            System.out.println(Thread.currentThread().getName()+ " locked: 10S");
        } catch (InterruptedException e) {
            logger.error("", e);
        } finally {
            lock.unlock(); //java.lang.IllegalMonitorStateException: attempt to unlock lock, not locked by current thread by node id
        }
    }
}
